home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
vtkerma1.arc
/
MSMENU.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-02-13
|
27KB
|
1,050 lines
PAGE 59, 132
TITLE MsMenu -- Dynamic menu generator for Kermit and descendents
; Update 6 Jan 86
IF1
%OUT >> Starting pass 1
ELSE
%OUT >> Starting pass 2
ENDIF
PUBLIC Menu, Quick_menu, Menu_file_name, Reload_menu_flag
;***************************************************************************
; *Definitions* ...
; Global defs
INCLUDE MsDefs.H
Color_attr=30h ; Black on Cyan
Color_highlight=1Eh ; Yellow on Blue
Color_header_attr=74h ; Red on White
Mono_attr=70h ; Black on white
Mono_highlight=07h ; White on black
Upper_left=218 ; Box drawing chars
Upper_right=191
Lower_left=192
Lower_right=217
Horizontal=196
Vertical=179
Left_tee=180
Right_tee=195
Screen EQU 10h ; BIOS screen call
Kb EQU 16h ; BIOS keyboard call
Number_of_columns EQU 80 ; Width in characters
Number_of_rows_PC EQU 25 ; Length in rows including mode line
Number_of_chars_on_PC_screen EQU Number_of_columns*Number_of_rows_PC
; Number of chars in IBM screen
; Flags in Screen_flags (in MSYIBM)
Screen_changed EQU 8 ; Data on more than one line changed
Force_screen_update EQU 10h ; Update every character of both video pages,
; (on color card), which is slower than
; mollasses in January
; Scan codes for keys we have predefined ...
Escape_key EQU 1
Space_key EQU 57
F6_key EQU 64
ALT_F6_key EQU 109
Left_key EQU 75
Right_key EQU 77
Up_key EQU 72
Down_key EQU 80
PgUp_key EQU 73
PgDn_key EQU 81
Home_key EQU 71
End_key EQU 79
Return_key EQU 28
Seg_is_Alloc MACRO
call Use_our_own_ds
ASSUME ds:MAlloc, es:MAlloc
ENDM
Seg_is_Datas MACRO
call Back_to_normal_ds
ASSUME ds:DataS, es:DataS
ENDM
DataS SEGMENT PUBLIC 'DataS'
EXTRN Which_page:BYTE, Screen_flags:BYTE, Old_Image:WORD
EXTRN Video_page_addresses:WORD, m7171:BYTE, In_menu_mode:BYTE
EXTRN Force_mono:BYTE, m7171:BYTE, TakAdr:WORD, TakLev:BYTE
Menu_file_name LABEL BYTE
Program_name
DB '.MNU', 60 DUP (0)
Saved_mode_line DW Number_of_columns DUP (?) ; Saved image of Mode line
Characters LABEL BYTE
DB Home_key, End_key, PgUp_key
DB PgDn_key, Up_key, Down_key
DB Left_key, Right_key, Return_key
N_Characters EQU $-Characters
Actions LABEL WORD
DW Do_Home, Do_End, Do_PgUp
DW Do_PgDn, Do_Up, Do_Down
DW Do_Up, Do_Down, Do_Return
DW Do_other
No_memory DB ' *** Not enough memory for MENU -- Press any key to continue ***$'
Cr_str DB Cr, '$'
Cant_find_file DB ' ***** Missing '
Program_name
DB '.MNU -- Press any key to continue *****$'
Ctrl_C_static_text DB 'Set Mode Command',0,0
Ctrl_C_stext_len EQU $ - Ctrl_C_static_text
Reload_menu_flag DB 0 ; Flag that file needs reloading
DataS ENDS
; Dummy segment for allocated memory
MAlloc SEGMENT AT 0
Menu_items DW 20 DUP (?) ; Ptrs to texts for menu item names
Menu_data DW 20 DUP (?) ; Ptrs to data for menu items
Ctrl_C_ptr DW 1 DUP (?) ; Ptr to ^C data line
N_items DW ? ; The number of items in our list
File_handle DW ? ; File handle for menu file
Which_item DW ? ; Item number we are on, from 0
Last_item DW ? ; Number of the last item
Width_counter DW ? ; Working counter of chars per line
Item_width DW ? ; Number of characters per item
Header_ptr DW ? ; OFFSET of Header text
Header_length DW ? ; Length of Header text
Menu_window_top DW ? ; Topmost row of menu
Menu_window_left DW ? ; Leftmost column of menu
Full_keystroke DW ? ; Scan code in high half, ASCII value in low
Which_line DW ? ; Current line number on screen
Our_cursor DW ? ; Our position
Our_Image DW Number_of_chars_on_PC_screen DUP (?) ; Our buffer
Menu_database DB 100*74 DUP (?) ; Where we store the Menu text
Menu_file_buffer DB 2048 DUP (?) ; Buffer for reading Menu file from disk
Unhighlight DB ? ; Normal attribute
Highlight DB ? ; Highlighted attribute
Header_attribute DB ? ; Header line attribute
Ctrl_C_data DB 20 DUP (?) ; Place to hold ^C text
End_MAlloc LABEL BYTE ; Ptr to end of what we need
MAlloc ENDS
Code SEGMENT PUBLIC
EXTRN Put_Screen:NEAR, Get_Screen_Segment:NEAR, Boop:NEAR
EXTRN Which_card:BYTE, SPath:NEAR, Check_table:NEAR
EXTRN Get_memory_block:NEAR, PutErr_PC:NEAR, Screen_Image_ptr:DWORD
EXTRN Mode_line_ptr:DWORD, Comnd:NEAR, Go_to_page_zero:NEAR
EXTRN Save_command_mode_screen:NEAR, Restore_command_mode_screen:NEAR
ASSUME CS:Code, DS:DataS, ES:DataS
Normal_ds DW ? ; Ptr back to ds on entry
MAlloc_ds DW ? ; Address of MAlloc segment
MFlags DB 0 ; Internal flags, kept in code segment
; for easy access
Bye_bye EQU 1 ; Flag to leave
Been_here EQU 2 ; Already did once-only initialization
Newlin EQU 4 ; We are at the start of a text line
New_item EQU 8 ; We have seen an item but no data yet
In_header EQU 10h ; In a header definition
Menu PROC
mov ah, CmCfm
call Comnd ; Get a confirm
jmp R
Quick_menu:
call Do_menu ; Call routine to do the work
nop
nop
nop
jmp RSkp ; We return skip no matter what
Do_menu:
and cs:MFlags, NOT Bye_bye ; Flag that we aren't leaving yet
test cs:MFlags, Been_here ; Been here before?
jz MNU_go ; No ...
; We have been here before, so we already have memory allocated ...
; Do we need to reload the database?
cmp Reload_menu_flag, 0 ; Is the flag to reload set?
jne MNU_reload ; Yes, reload it
call Use_our_own_ds ; Switch to Alloc segment
call Install_screen ; Save, then blank the background
jmp SHORT MNU_1 ; Go use the database we already have set up
MNU_reload:
mov Reload_menu_flag, 0 ; Clear flag for next time
mov ax, MAlloc_ds ; Reuse old memory
jmp SHORT H_ok ; Join common code
MNU_go:
; First, get some memory to work in
; *** The silly assembler won't let me do this, saying
; Constant was expected
; SHR is an assembly-time operator according to the manual, so this
; construct should be legit.
; Still a problem from IBM MASM 1.0 up to and including Microsoft MASM
; version 4.0. [tested jan 86]
; mov bx, (OFFSET End_MAlloc+15) SHR 4 ; Lowest location we don't use,
; round up to next higher paragraph,
; then convert to number of paragraphs
mov bx, OFFSET End_MAlloc+15 ; Round up to next paragraph
mov cl, 4 ; Shift count
shr bx, cl ; Shift to get number of paras we need
call Get_memory_block ; Get a memory block of the right size
jnc H_OK ; Ok so far ...
mov dx, OFFSET No_memory ; Complain
jmp Do_mode_line_error ; Display noisy error message, wait for
; keystroke, then exit, restoring
; clobbered mode line
H_OK: mov MAlloc_ds, ax ; Save the address of our block
mov bx, ds ; Set up ptr back to ds
mov Normal_ds, bx ; Save ptr back to old one
Seg_is_Alloc ; Alloc segment
call Build_Menu_database ; Build the database
test cs:MFlags, Bye_bye ; Time to leave?
jz MNU_0 ; Not yet
; *** Properly speaking, we really ought to release the memory we
; were just allocated, since we can't use it ... maybe later ***
jmp Back_to_normal_ds ; Oh well ...
ASSUME ds:MAlloc, es:MAlloc
MNU_0: or cs:MFlags, Been_here ; Flag for later
call Install_screen ; Set up to call Put_Screen
add Item_width, 2 ; Add in some padding for menu items
mov ax, 78 ; Determine the number of spaces to the
sub ax, Item_width ; left of the menu
shr ax, 1 ; Divide leftover by two
mov Menu_window_left, ax ; Store the answer
mov ax, 21 ; Count lines outside window
sub ax, N_items ; Subtract for items (4 others preallocated)
shr ax, 1 ; Divide total rows by 2
mov Menu_window_top, ax ; Store the answer
MNU_1: call Build_menu_box ; Build outline / background for Menu window
call Fill_menu_frame ; Put menu items and header in frame
mov Which_item, 0 ; This is the one we want
call Highlight_line ; Make it stand out
MNU_2: call Do_the_screen ; Display this frame
call Check_keystrokes ; See what to do next
test cs:MFlags, Bye_bye ; Time to leave?
jz MNU_2 ; No, go update the frame
Seg_is_Datas ; Datas segment
call Set_up_macro ; Set up a macro to run when we get out
call Go_to_page_zero ; Back to normal
jmp Restore_command_mode_screen
PUBLIC Set_up_macro
Set_up_macro:
mov ax, MAlloc_ds ; MAlloc segment
mov ds, ax ; Install in ds
ASSUME ds:MAlloc
cld ; Forwards
inc TakLev ; Bump take level
add takadr, SIZE takinfo ; Address new take frame
mov bx, Which_item ; Item number that was selected
shl bx, 1 ; Double for word offset
mov si, Menu_data[bx] ; Pick up pointer to data for this item
mov bx, es:TakAdr ; Get TAKE frame addr into bx
mov BYTE PTR es:[bx].TakFcb, 0FFh ; Mark as a macro
lea di, es:[bx].TakBuf ; Put it in the TAKE buffer
sub cx, cx ; Clear counter
CPC_1: lodsb ; Get a byte
or al, al ; Null?
jne CPC_3
mov al, Cr ; Load up a Cr for end-of-line
stosb ; Store it
inc cx ; Count this char
lodsb ; Is there another data line?
cmp al, "+" ; Well?
jne CPC_4 ; No, quit
jmp CPC_1 ; Go do the next line of data
CPC_3: stosb ; Deposit char
inc cx ; Count this char
or al, al ; Hit end?
jne CPC_1 ; No
PUBLIC CPC_4, CPC_1, CPC_ret, CPC_3
CPC_4: lea ax, es:[bx].takbuf ; Pick up ptr to start of TAKE buffer
mov es:[bx].takptr, ax ; Init buffer ptr
mov es:[bx].takchl, cl ; Chars remaining
mov es:[bx].takcnt, cx ; and all chars
mov es:[bx].takcnt+2, 0 ; Clear high order half
CPC_ret:
mov ax, Normal_ds ; DataS segment
mov ds, ax ; Install in ds
ASSUME ds:DataS
ret ; Done here
Bombed: call Boop ; Bombed, make a noise
or cs:MFlags, Bye_bye ; Go home
ret
PUBLIC Build_Menu_database
ASSUME ds:MAlloc, es:MAlloc
Build_Menu_database:
mov ax, Normal_ds ; Switch ds to DataS
mov ds, ax
ASSUME ds:DataS
mov si, OFFSET Ctrl_C_static_text ; Ptr to source
mov di, OFFSET Ctrl_C_data ; Ptr to target
cld ; Forwards
mov cx, Ctrl_C_stext_len ; The number of bytes to copy
rep movsb ; Copy the string
mov ax, MAlloc_ds ; Switch ds back to MAlloc
mov ds, ax
ASSUME ds:Malloc
mov ax, OFFSET Ctrl_C_data ; Pick up ptr to control-C text
mov Ctrl_C_ptr, ax ; Store it away for later
mov N_items, 0 ; No items yet
mov Item_width, 0 ; This is the widest item seen so far
Seg_is_Datas ; Datas segment
mov ax, OFFSET Menu_file_name ; Name of file to get
call spath ; Search path for file, DSK: first
jnc BUI_ok ; Got it, go work with it
mov dx, OFFSET Cant_find_file ; Complain
call Do_mode_line_error ; Wait for a key
jmp Use_our_own_ds ; Reset ds and return NG
BUI_ok: mov dx, ax ; Copy ptr to name to dx
mov ax, (Open2*100h) + 0 ; Open file for input
int DOS ; Try to open the file
jc Bombed ; Huh?
Seg_is_Alloc ; Alloc segment
mov File_handle, ax ; Save file handle for later
mov di, OFFSET Menu_database ; Ptr to start of our database
cld ; Build forwards
or MFlags, Newlin ; We start on a new line
BUI_disk_read:
mov ah, ReadF2 ; Code to read from file
mov bx, File_handle ; DOS file handle
mov cx, SIZE Menu_file_buffer ; Number of characters to try for
mov dx, OFFSET Menu_file_buffer ; Where to put them
int DOS ; Read from the Menu file
jc BUI_finish ; Stop on error
or ax, ax ; Check for zero bytes read
jz BUI_finish ; Hit EOF, go finish it up
mov cx, ax ; Byte count for this record
inc cx ; We decr once too many times
mov si, OFFSET Menu_file_buffer ; Ptr to buffer
BUI_lp: loop BUI_next_char ; If more chars, go get one
jmp SHORT BUI_disk_read ; Buffer is empty, try to refill it
BUI_next_char:
lodsb ; Get the next byte
cmp al, Space ; In the control-char range?
jl BUI_control ; Yes, don't store it, check for linefeed
stosb ; Store the char
test MFlags, Newlin ; At start of a line?
jz BUI_not_first_char ; No
call BUI_do_first_char ; Use routine to do it
jmp BUI_lp
BUI_not_first_char:
inc Width_counter ; Track the size of each line
jmp Bui_lp ; Go try for another char
%OUT >> About half way through source file
BUI_control:
cmp al, Lf ; Line feed?
jne BUI_lp ; No
or MFlags, Newlin ; We are now on a new line
sub al, al ; Make a zero
stosb ; Tie off the last line
test MFlags, New_item + In_header ; Was this an item or hdr line?
jz BUI_lp ; No
mov ax, Width_counter ; Pick up current width
test MFlags, In_header ; Header?
jz BUI_tag ; No
mov Header_length, ax ; Save length for header centering
BUI_tag:
cmp ax, Item_width ; Compare with previous maximum
jle BUI_lp ; Not bigger
mov Item_width, ax ; Save this new maximum
jmp BUI_lp ; Go get another character
BUI_finish:
mov ax, N_items ; Count of items
dec ax ; Drop by 1
mov Last_item, ax ; Store as number of last item
sub al, al ; Make a zero
mov cx, 13 ; Make several blank lines after Menu database
rep stosb ; Write a string of zeros
mov ah, 3eh ; Code to close a file
int DOS ; Close the file
ret ; Done here
BUI_do_first_char:
and MFlags, NOT (Newlin + In_header) ; Turn off some flags
mov Width_counter, 0 ; Start line length counter to zero
cmp al, "%" ; Code for header?
jne DFC_not_hdr ; No
mov Header_ptr, di ; Store header pointer for later
or MFlags, In_header ; We want special length tracking
jmp SHORT DFC_ret
DFC_Not_hdr:
cmp al, "*" ; Code for item?
jne DFC_not_item ; No
mov bx, N_items ; Get pointer to the current row
shl bx, 1 ; Double for word offset
mov Menu_items[bx], di ; Store pointer to the item
inc N_items ; This is a new item, add one to the count
or MFlags, New_item ; Flag that we need a data pointer
jmp SHORT DFC_ret
DFC_Not_item:
cmp al, "+" ; Code for data?
jne DFC_ret ; No
test MFlags, New_item ; Only store ptr to the first line of data
jz DFC_ret ; Ignore this one, ptr already set
mov bx, N_items ; Get pointer to the current row
dec bx ; Pull back to previous row
shl bx, 1 ; Double for word offset
mov Menu_data[bx], di ; Store pointer to the data
and MFlags, NOT New_item ; Clear flag for next time
DFC_ret:
ret ; Done here
Install_Screen:
Seg_is_Datas ; Datas segment
call Save_command_mode_screen ; First, save what is already up there
Seg_is_Alloc ; Alloc segment
mov ax, 0720h ; White blanks on black background
mov di, OFFSET Our_Image ; Ptr to our buffer
mov cx, Number_of_chars_on_PC_screen
cld ; Forwards
rep stosw ; Clear our buffer
mov bx, OFFSET Our_Image ; Ptr to our buffer
mov ax, Normal_ds ; Use normal again
mov ds, ax ; Install in ds
ASSUME ds:DataS
or Screen_flags, Force_screen_update
call Put_Screen ; Set up both video pages
mov ax, MAlloc_ds ; Use our own segment
mov ds, ax ; Install in ds
ASSUME ds:MAlloc
ret
PUBLIC Build_menu_box
Build_menu_box:
; Set up proper attribute based on card type
mov ah, Mono_attr ; Mono
mov Unhighlight, ah
mov ah, Mono_highlight
mov Highlight, ah
mov Header_attribute, ah
Seg_is_Datas ; Datas segment
cmp Force_mono, 0 ; Are we stuck with mono?
jne MON_0 ; Yes
call Get_Screen_Segment
cmp ax, 0b000h ; Mono?
je MON_0 ; It is, go use it
Seg_is_Alloc ; Alloc segment
mov ah, Color_attr ; Color, use it instead
mov Unhighlight, ah
mov ah, Color_highlight
mov Highlight, ah
mov ah, Color_header_attr
mov Header_attribute, ah
jmp SHORT MON_1
MON_0:
Seg_is_Alloc ; Alloc segment
MON_1: mov ax, Menu_window_top ; Row number of top of window
mov Which_line, ax ; Save it for later
call Make_new_ptr ; Get a new DI
; Do top row of Menu window
mov al, Upper_left ; Graphic character for upper left corner
mov ah, Unhighlight ; Attribute for no highlighting
stosw
mov al, Horizontal
mov cx, Item_width
rep stosw
mov al, Upper_right
stosw
inc Which_line ; Bump to next row
call Make_new_ptr ; Point to it
mov al, Vertical
stosw
mov al, Space ; Do the header line
mov ah, Header_attribute
mov cx, Item_width
rep stosw
mov al, Vertical
mov ah, Unhighlight
stosw
inc Which_line ; Bump to next row
call Make_new_ptr ; Point to it
mov al, Right_tee
stosw
mov al, Horizontal
mov cx, Item_width
rep stosw
mov al, Left_tee
stosw
inc Which_line ; Bump to next row
call Make_new_ptr ; Point to it
mov cx, N_items ; Do one line for each item
; Do the middle rows of the Menu window
LP_1: push cx
mov al, Vertical
stosw
mov al, Space
mov cx, Item_width
rep stosw
mov al, Vertical
stosw
pop cx
inc Which_line ; Bump to next row
call Make_new_ptr ; Point to it
loop LP_1
; Do bottom row of Menu window
mov al, Lower_left
stosw
mov al, Horizontal
mov cx, Item_width
rep stosw
mov al, Lower_right
stosw
mov Our_cursor, (25*256)+0 ; Put cursor where it won't be seen
ret
; Make ptr to another item
New_line:
mov di, Which_item ; Number of the menu item we are doing
add di, Menu_window_top ; Adjust for top of list of menu items
add di, 3
mov Which_line, di ; Set up as the line to work on
; jmp Make_new_ptr ; Make a new pointer to the line
; Set up a pointer to this row
Make_new_ptr:
push ax ; Save reg
push bx
mov ax, Which_line ; Row number of topmost row
mov bh, 2 * Number_of_columns ; Convert to bytes
mul bh
add ax, Menu_window_left ; Account for columns to the left
add ax, Menu_window_left
add ax, OFFSET Our_Image ; Finally, add in the address of the buffer
mov di, ax ; Set up as destination
pop bx
pop ax
ret ; Go use it
PUBLIC Fill_menu_frame
Fill_menu_frame:
mov ax, Menu_window_top ; Row number to start writing to
inc ax ; Bump it again
mov Which_line, ax ; Save it
call Make_new_ptr ; Get a new DI
add di, 2 ; Skip over border
mov bx, Item_width ; Pick up item width
sub bx, Header_length ; Subtract length of header
; bx := bx / 2 for centering
; bx := bx * 2 for byte-to-word conversion
and bx, NOT 1 ; Force it EVEN
add di, bx ; Adjust ptr for Header centering
; Do the header
mov si, Header_ptr ; Use the header text here
F00_lp_inner:
lodsb ; Pick up the next byte
or al, al ; Check for zero
jz F00_tag ; Hit end
stosb ; Store this char
inc di ; Skip attribute
jmp F00_lp_inner ; Go do another char
; Do the items
F00_tag:
mov Which_item, 0 ; Start on item zero
FIL_lp_outer:
mov bx, Which_item ; Item we are on
shl bx, 1 ; Double for word offset
mov si, Menu_items[bx] ; Ptr to item text
call New_line ; Set up di for this line
add di, 4 ; Skip over the border and one space
FIL_lp_inner:
lodsb ; Pick up the next byte
or al, al ; Check for zero
jz FIL_end_of_inner ; Hit end
stosb ; Store this char
inc di ; Skip attribute
jmp FIL_lp_inner ; Go do another char
; End of inner loop, skip chars until we hit a zero byte
FIL_end_of_inner:
inc Which_item ; Bump to next item
mov ax, Which_item ; Get it in ax
cmp ax, Last_item ; Over the hill?
jle FIL_keep_going
ret ; Done filling
FIL_keep_going:
inc Which_line ; Move to next row
call Make_new_ptr ; Get a new DI
add di, 4 ; Skip over border and first column
jmp FIL_lp_outer ; Go try for another line
PUBLIC Do_other
Do_other:
Seg_is_Alloc ; Alloc segment
cmp BYTE PTR Full_keystroke, 3 ; Was it a control-C?
jne DOT_0 ; No
mov Which_item, 20 ; Pretend item 20
jmp Do_return ; Pretend selected
DOT_0: mov bx, Which_item ; The current item
mov Which_line, bx ; Save it in another place
mov ah, BYTE PTR Full_keystroke ; Pick up ASCII value of key user hit
cmp ah, 'a' ; Compare with lower case 'a'
jb DOT_loop ; Too low
cmp ah, 'z' ; Compare with lower case 'z'
ja DOT_loop ; Too high
sub ah, 32 ; Upcase this character
DOT_loop:
push bx ; Save reg
shl bx, 1 ; Double for word offset
mov si, Menu_items[bx] ; Get ptr to item text string
pop bx ; Restore reg
lodsb ; Get the first letter
cmp al, 'a' ; Compare with lower case 'a'
jb DOT_No_upcase ; Too low
cmp al, 'z' ; Compare with lower case 'z'
ja DOT_No_upcase ; Too high
sub al, 32 ; Upcase this character
DOT_No_upcase:
cmp al, ah ; Do we have a winner?
jne No_match ; Not yet ...
; Have a hit ...
push bx ; Save new line
mov bx, Which_line ; Get back ptr to old line
mov Which_item, bx ; Set up for highlight routine
call Unhighlight_line ; Unhiughlight the old line
pop WORD PTR Which_item ; Get back new line
call Highlight_line ; Highlight it
call Do_the_screen ; Show these changes ...
jmp Do_return ; Treat as if Return pressed while on this
No_match:
mov bx, Which_item ; Item we are pointing to now
inc bx ; Go up by 1
cmp bx, Last_item ; Did we go too high?
jle No_prob ; No problem
sub bx, bx ; Move to the first item instead
No_prob:
mov Which_item, bx ; Store the new item number
cmp bx, Which_line ; Back to start?
je Do_boop ; Yeah, complain
jmp DOT_loop ; Go try the next one
Do_boop:
Seg_is_Datas ; Datas segment
call Boop ; Give low beep
Seg_is_Alloc ; Alloc segment
; jmp Check_keystrokes ; Try again
Check_keystrokes:
mov ah, 1 ; Code to see if a char is ready
int Kb ; Have BIOS tell us
jz Check_keystrokes ; None, waste time
sub ah, ah ; Zero is code to read the char
int Kb ; Have BIOS get it for us
mov Full_keystroke, ax ; Save the whole thing here
Seg_is_Datas ; Datas segment
mov al, ah ; Copy scan code to al
mov bx, OFFSET Actions ; Action table
mov cx, N_Characters ; Number of scan codes to check
mov dx, OFFSET Characters ; The character table
jmp Check_Table ; Go dispatch to the right routine
ASSUME ds:Malloc, es:MAlloc
Do_the_screen:
mov bx, OFFSET Our_Image ; Set ptr to our screen
mov ax, Normal_ds ; Put_Screen likes normal ds
mov ds, ax
ASSUME ds:DataS
or Screen_flags, Screen_changed ; Flag that Put_Screen has to work
call Put_Screen ; Update screen
mov ax, es ; Copy es ...
mov ds, ax ; ... to ds
ASSUME ds:MAlloc
ret ; Done here
Move_highlight_up:
Seg_is_Alloc ; Alloc segment
call Unhighlight_line
call Move_up
jmp Highlight_line
Move_highlight_down:
Seg_is_Alloc ; Alloc segment
call Unhighlight_line
call Move_down
jmp Highlight_line
Do_Home:
Seg_is_Alloc ; Alloc segment
call Unhighlight_line
mov Which_item, 0 ; Item 0
jmp Highlight_line
Do_End:
Seg_is_Alloc ; Alloc segment
call Unhighlight_line
mov ax, Last_item ; Final item on menu
mov Which_item, ax
jmp Highlight_line
Do_PgUp:
jmp Do_Home
Do_PgDn:
jmp Do_End
Do_Up:
jmp Move_highlight_up
Do_Down:
jmp Move_highlight_down
Do_return:
; jmp CHK_bye
CHK_bye:
Seg_is_Alloc ; Alloc segment
or cs:MFlags, Bye_bye ; Flag the exit
ret ; Done here
Highlight_line:
mov al, Highlight ; Set up to highlight the chars
jmp SHORT Change_highlighting
Unhighlight_line:
mov al, Unhighlight ; Set up to unhighlight the chars
; jmp Change_highlighting
Change_highlighting:
call New_line
add di, 3 ; Skip over border, point at attribute
Seg_is_Alloc ; Alloc segment
mov cx, Item_width ; The number of attributes to hit
HIL_lp: stosb
inc di
loop HIL_lp ; Try for another
ret
Move_up:
mov ax, Which_item ; Item we arte pointing to now
dec ax ; Go up by 1
or ax, ax ; See if negative
jns Move_is_OK ; No problem
mov ax, Last_item ; Move to the last item instead
jmp SHORT Move_is_OK
Move_down:
mov ax, Which_item ; Item we are pointing to now
inc ax ; Go up by 1
cmp ax, Last_item ; Did we go too high?
jle Move_is_OK ; No problem
sub ax, ax ; Move to the first item instead
Move_is_OK:
mov Which_item, ax ; Store the new item number
ret ; That's it
Back_to_normal_ds:
push ax ; Save reg
mov ax, Normal_ds ; Pick up addr of DataS segment
mov ds, ax ; Copy to ds
nop
mov es, ax ; and es
pop ax ; Restore reg
ret ; and return
ASSUME ds:DataS, es:DataS
Use_our_own_ds:
push ax ; Save reg
mov ax, MAlloc_ds ; Pick up addr of MAlloc segment
mov ds, ax ; Copy to ds
nop
mov es, ax ; and es
pop ax ; Restore reg
ret ; and return
Menu ENDP
Do_mode_line_error PROC
mov In_menu_mode, 0 ; Leave menu mode, if in it
call Save_mode_line ; Ask for a save
call PutErr_PC ; Play with mode line
call Bombed ; Make noise
sub ah, ah ; Code to read a character
int Kb ; Wait until user hits key
call Restore_mode_line ; Ask for a restore
mov ah, PrStr ; Code to type a string
mov dx, OFFSET Cr_str ; Simple carriage return
int Dos ; Type it (force left margin)
ret ; Done here
Do_mode_line_error ENDP
; Save the mode line for later restoral
Save_mode_line PROC
push ds ; Save ds
call Get_address ; Get new ds into ax
mov ds, ax ; Store the new seg addr
mov si, (Number_of_rows_PC-1)*2*Number_of_columns ; Offset of line 25
mov di, OFFSET Saved_mode_line ; Where to copy it
mov cx, Number_of_columns
cld ; Forwards
rep movsw ; Save the line
pop ds ; Restore ds
ret
Save_mode_line ENDP
; Restore the mode line
Restore_mode_line PROC
push es ; Save es
call Get_address ; Get new es into ax
mov es, ax ; Store the new seg addr
mov si, OFFSET Saved_mode_line ; Where copy is
mov di, (Number_of_rows_PC-1)*2*Number_of_columns ; Offset of line 25
mov cx, Number_of_columns
rep movsw ; Restore the line
pop es ; Restore es
ret
Restore_mode_line ENDP
; Get address of segment of currently-displayed video page
Get_address PROC
mov ax, 0B000h ; Mono, maybe
cmp Which_card, 0 ; Is it?
je Go_back ; Yes
sub bh, bh ; Zero high half of bx
mov bl, Which_page ; The page we are on in the color card
shl bx, 1 ; Double for word offset into table
mov ax, Video_page_addresses[bx] ; Pick up the address for the page
Go_back:
ret
Get_address ENDP
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret
R PROC
ret
R ENDP
Code ENDS
END